/**  
 * All rights Reserved, Designed By www.tydic.com
 * @Title:  TaskServiceImpl.java   
 * @Package com.axin.service.impl   
 * @Description:    TODO(用一句话描述该文件做什么)   
 * @author: axin     
 * @date:   2019年4月21日 下午4:07:56   
 * @version V1.0 
 * @Copyright: 2019 www.hao456.top Inc. All rights reserved. 
 */
package com.axin.service.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.axin.common.entity.ApiToken;
import com.axin.common.entity.DataGridResult;
import com.axin.common.entity.PageObject;
import com.axin.common.entity.response.BalanceBean;
import com.axin.common.entity.response.OrdersDetail;
import com.axin.common.exception.AccountLockException;
import com.axin.common.exception.ApiException;
import com.axin.common.exception.BalanceNotEnoughException;
import com.axin.common.exception.UpdateRuntimeException;
import com.axin.common.utils.IDUtils;
import com.axin.common.utils.JobUtil;
import com.axin.common.utils.ListPageHelper;
import com.axin.dao.HbTaskMapper;
import com.axin.entity.HbSymbols;
import com.axin.entity.HbTask;
import com.axin.entity.HbTrades;
import com.axin.entity.example.HbTaskExample;
import com.axin.service.AccountService;
import com.axin.service.CommonService;
import com.axin.service.MessageService;
import com.axin.service.OrderService;
import com.axin.service.TaskService;
import com.axin.service.TradesService;

/**   
 * @Description: TODO 
 * @ClassName:  TaskServiceImpl
 * @author:  Axin 
 * @date:   2019年4月21日 下午4:07:56   
 * @Copyright: 2019 www.hao456.top Inc. All rights reserved. 
 */
@Service
public class TaskServiceImpl implements TaskService{

	
	@Autowired
	private HbTaskMapper taskMapper;
	
	@Autowired
	private MessageService messageService;
	
	@Autowired
	private AccountService accountService;
	
	@Autowired
	private CommonService commonService;
	
	@Autowired
	private OrderService orderService;
	
	@Autowired
	private TradesService tradesService;
	
	
	/* (non-Javadoc)
	 * @see com.axin.service.TaskService#getTaskById(java.lang.Long)
	 */
	@Override
	public HbTask getTaskById(Long id) {
		
		HbTask task = this.taskMapper.selectByPrimaryKey(id);
		
		if("-1".equals(task.getState())){
			throw new RuntimeException("该任务已被关闭，不允许编辑");
		}
		/*HbTask task = new HbTask();
		task.setId(id);
		task.setUserId(10000L);
		task.setBuyTradeCount(0);
		task.setBuyTradeLimit(1);//系统自动买入单数上限
		task.setSymbol("bttusdt");
		task.setFirstMoney("1");
		task.setBuyLevel("3");
		task.setBuyMethod("1");
		task.setBuyBasePrice("0.00066711");
		task.setProfitPercent("0.1");//%
		task.setTotalAmount("1496");
		task.setTotalMoney("1");*/
		return task;
		
	}

	
	
	/* (non-Javadoc)
	 * @see com.axin.service.TaskService#getTaskByParam(com.axin.entity.HbTask)
	 */
	@Override
	public List<HbTask> getUnClosedTaskBySymbol(Long userId, String symbol){
		HbTaskExample example = new HbTaskExample();
		List<String> states = new ArrayList<>();
		states.add("0");
		states.add("1");
		example.createCriteria().andUserIdEqualTo(userId)
								.andSymbolEqualTo(symbol)
								.andStateIn(states);
		List<HbTask> list = this.taskMapper.selectByExample(example);
		return list;
	}



	/* (non-Javadoc)
	 * @see com.axin.service.TaskService#saveTask(java.lang.Long, com.axin.entity.HbTask)
	 */
	@Override
	public void saveTask(Long userId, HbTask task) {
		task.setId(IDUtils.randomId());
		task.setSymbol(task.getSymbol().trim());
		task.setUserId(userId);
		task.setCreateTime(new Date());
		this.taskMapper.insertSelective(task);
	}

	/* (non-Javadoc)
	 * @see com.axin.service.TaskService#getList(com.axin.common.entity.PageObject, com.axin.entity.HbTask)
	 */
	@Override
	public DataGridResult getListByParam(PageObject page, HbTask task) {
		HbTaskExample example = new HbTaskExample();
		example.createCriteria().andUserIdEqualTo(task.getUserId());
		List<HbTask> list = this.taskMapper.selectByExample(example);
		
		int size = list.size();
		 if(page != null){
			 ListPageHelper<HbTask> pageHelper = new ListPageHelper<>();
			 try {
				list = pageHelper.page(page.getPage(), page.getRows(), list);
			} catch (Exception e) {
				e.printStackTrace();
			}
		 }
		 
		 return new DataGridResult(size,list);
	}
	
	
	
	@Override
	public void updateTaskById(HbTask task, Long userId){
		task.setUpdateTime(new Date());
		this.taskMapper.updateByPrimaryKeySelective(task);
		//WebSocket通知前端更新任务列表
		try {
			messageService.sendTaskUpdateNotify(userId);
		} catch (Exception e) {
		}
		
	}
	
	
	public void closeTaskById(Long id){
		HbTask t = this.taskMapper.selectByPrimaryKey(id);
		String state = t.getState();
		if("1".equals(state)){
			throw new UpdateRuntimeException("当前任务正在运行中，不允许关闭");
		}else{
			HbTask task = new HbTask();
			task.setId(id);
			task.setUpdateTime(new Date());
			task.setState("-1");
			this.taskMapper.updateByPrimaryKeySelective(task);
		}
		
	}



	/* (non-Javadoc)
	 * @see com.axin.service.TaskService#updateTaskById(com.axin.entity.HbTask)
	 */
	@Override
	public void updateTaskById(HbTask task,ApiToken token) {
		
		Long id = task.getId();
		HbTask entity = this.taskMapper.selectByPrimaryKey(id);
		
		if("1".equals(entity.getState())){
			throw new RuntimeException("请停止任务后再进行修改。");
		}
		if("-1".equals(entity.getState())){
			throw new RuntimeException("任务已关闭，不允许修改。");
		}
		String symbol = entity.getSymbol();
		Integer buyTradeCount = entity.getBuyTradeCount();
		String firstMoney = entity.getFirstMoney();
		
		Integer buyTradeLimit = task.getBuyTradeLimit();
		String buyMethod = task.getBuyMethod();
		if(buyTradeCount > 0){
			if(buyTradeLimit < buyTradeCount){
				throw new RuntimeException("本轮购买交易次数已经达"+buyTradeCount+"次，购买交易上限不能低于"+buyTradeCount);
			}
			HbSymbols hbSymbol = this.commonService.selectLocalSymbolsBySymbol(symbol);
			int moneyScale = hbSymbol.getPricePrecision();
			String quoteCurrency = hbSymbol.getQuoteCurrency();
			
			String[] strs = JobUtil.getStrategyMoney(firstMoney, buyTradeLimit, moneyScale,buyMethod);
			
			/**
			 * 1 2 3 4 5
			 * 0 1 2 3 4 
			 * */
			BigDecimal total = new BigDecimal(0);
			for (int i = buyTradeCount; i < strs.length; i++) {
				total = total.add(new BigDecimal(strs[i]));
			}
			try {
				//账户id
				Integer accountId = this.accountService.getAccountsByType(token, AccountService.TYPE_SPOT);
				
				BalanceBean balance = this.accountService.getBalanceByAccountId(token, accountId, AccountService.BALANCE_TYPE_TRADE, quoteCurrency);
				BigDecimal balanceBig = new BigDecimal(balance.getBalance()).setScale(moneyScale, BigDecimal.ROUND_HALF_UP);
				
				//根据首单金额和策略判断账户资金是否足够
  				if(balanceBig.compareTo(total) < 0){
  					BigDecimal diff = total.subtract(balanceBig).setScale(moneyScale, BigDecimal.ROUND_HALF_UP);
  					throw new BalanceNotEnoughException("根据您本次修改的参数，系统计算本轮交易所需余额不足！差额"+diff.toPlainString()+", 请保证余额充足或修改参数后重试！");
  				}
				
			}catch (BalanceNotEnoughException e) {
					throw new RuntimeException(e.getMessage());
			}catch (Exception e) {
				throw new RuntimeException("任务修改失败，请重试！");
			}
			
		}
		//直接修改
		HbTask hbTask = new HbTask();
		hbTask.setId(id);
		hbTask.setFirstMoney(task.getFirstMoney());
		hbTask.setBuyTradeLimit(task.getBuyTradeLimit());
		hbTask.setBuyLevel(task.getBuyLevel());
		hbTask.setBuyMethod(task.getBuyMethod());
		hbTask.setReboundPercent(task.getReboundPercent());
		hbTask.setProfitPercent(task.getProfitPercent());
		hbTask.setFallBackPercent(task.getFallBackPercent());
		this.taskMapper.updateByPrimaryKeySelective(hbTask);
		
	}



	/* (non-Javadoc)
	 * @see com.axin.service.TaskService#sellById(com.axin.common.entity.ApiToken, java.lang.Long)
	 */
	@Override
	public void sellById(ApiToken token, Long userId,Long id) {
		HbTask task = this.taskMapper.selectByPrimaryKey(id);
		if(task == null) throw new RuntimeException("任务不存在");
		
		if("-1".equals(task.getState())){
			throw new RuntimeException("任务已关闭");
		}
		if("1".equals(task.getState())){
			throw new RuntimeException("请先停止任务，再执行。");
		}
		
		String symbol = task.getSymbol();
		Integer loopCount = task.getLoopCount();
		HbSymbols hbSymbol = this.commonService.selectLocalSymbolsBySymbol(symbol);
		int moneyScale = hbSymbol.getPricePrecision();
		int amountScale = hbSymbol.getAmountPrecision();
		String baseCurrency = hbSymbol.getBaseCurrency();
		
		
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		try {
			
			//账户id
			Integer accountId = this.accountService.getAccountsByType(token, AccountService.TYPE_SPOT);
			BalanceBean balance = this.accountService.getBalanceByAccountId(token, accountId, AccountService.BALANCE_TYPE_TRADE, baseCurrency);
			BigDecimal totalAmountBig = new BigDecimal(balance.getBalance()).setScale(amountScale, BigDecimal.ROUND_DOWN);//数量精度
			
			if(totalAmountBig.doubleValue() <= 0){
				throw new RuntimeException("持仓金币为0，无需卖出。");
			}
			
			String totalAmount = totalAmountBig.toPlainString();
			
			String totalMoney = task.getTotalMoney();
			BigDecimal totalMoneyBig = new BigDecimal(totalMoney == null ? "0.00" : totalMoney);//持仓金额
			
			
			Long orderId = this.orderService.createSellOrder(token, symbol, accountId, totalAmount);//卖出仓位所有币
			Thread.sleep(3000);//延迟3秒查询订单
			OrdersDetail ordersDetail = this.orderService.ordersDetail(token, orderId);
			String state = ordersDetail.getState();
			if("filled".equals(state)){
				BigDecimal fieldAmountBig = new BigDecimal(ordersDetail.getFieldAmount()).setScale(amountScale, BigDecimal.ROUND_HALF_UP);
				BigDecimal fieldMoneyBig = new BigDecimal(ordersDetail.getFieldCashAmount()).setScale(moneyScale, BigDecimal.ROUND_HALF_UP);
				//计算成交单价
				BigDecimal ave = fieldMoneyBig.divide(fieldAmountBig,moneyScale,BigDecimal.ROUND_HALF_UP);
				//计算实际收益率
				BigDecimal di = fieldMoneyBig.subtract(totalMoneyBig).setScale(moneyScale, BigDecimal.ROUND_HALF_UP);
				BigDecimal diPercent = di.divide(totalMoneyBig,5,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal("100")).setScale(2, BigDecimal.ROUND_HALF_UP);
				send(userId, "手动卖出成功，成交数量："+fieldAmountBig.toPlainString()+"， 成交金额："+fieldMoneyBig.toPlainString()+"， 成交单价："+ave.toPlainString()+"， 本轮收益金额："+di.toPlainString()+"，  实际收益率："+diPercent.toPlainString()+"%， ");
				
				//持久化到数据库 
				totalAmount = "0.00";
				totalMoney = "0.00";
				HbTask hbTask = new HbTask(id, 0, totalAmount, totalMoney);
				updateTaskById(hbTask, userId);
				
				//添加交易记录表
				long createTime = ordersDetail.getCreatedAt();
				Date date = new Date(createTime);
				HbTrades trades = new HbTrades(id, symbol, loopCount,"1", "2", fieldAmountBig.toPlainString(), fieldMoneyBig.toPlainString(), ave.toPlainString(), ordersDetail.getFieldFees(), sdf.format(date));
				trades.setTradeMode("2");
				this.tradesService.saveTrades(trades, userId);
			}else if("partial-filled".equals(state)){
				//获取完成的数量 在持有数量中减去
				//获取完成的金额 在持有金额中减去
				//重新计算均价，进行下一次比价
				
				BigDecimal fieldAmountBig = new BigDecimal(ordersDetail.getFieldAmount()).setScale(amountScale, BigDecimal.ROUND_HALF_UP);
				BigDecimal fieldMoneyBig = new BigDecimal(ordersDetail.getFieldCashAmount()).setScale(moneyScale, BigDecimal.ROUND_HALF_UP);
//				totalAmountBig = totalAmountBig.subtract(fieldAmountBig).setScale(amountScale, BigDecimal.ROUND_HALF_UP);
//				totalMoneyBig = totalMoneyBig.subtract(fieldMoneyBig).setScale(moneyScale, BigDecimal.ROUND_HALF_UP);
//				totalAmount = totalAmountBig.toPlainString();
//				totalMoney = totalMoneyBig.toPlainString();
				
				//计算成交均价
				BigDecimal ave = fieldMoneyBig.divide(fieldAmountBig,moneyScale,BigDecimal.ROUND_HALF_UP);
			
				send(userId, "手动部分卖出， 成交数量："+fieldAmountBig.toPlainString()+"， 成交金额："+fieldMoneyBig.toPlainString()+"， 成交单价："+ave.toPlainString());
				orderService.submitcancel(token, orderId);
				send(userId, "系统已撤消未完成订单");
				//持久化到数据库 
				//HbTask hbTask = new HbTask(id, null, totalAmount, totalMoney);
				//updateTaskById(hbTask, userId);
				
				//添加交易记录表
				long createTime = ordersDetail.getCreatedAt();
				Date date = new Date(createTime);
				BigDecimal fieldFeesBig = new BigDecimal(ordersDetail.getFieldFees()).setScale(moneyScale,BigDecimal.ROUND_DOWN);
				HbTrades trades = new HbTrades(id, symbol, loopCount,"1", "2", fieldAmountBig.toPlainString(), fieldMoneyBig.toPlainString(), ave.toPlainString(), fieldFeesBig.toPlainString(), sdf.format(date));
				trades.setTradeMode("2");//手动卖出
				this.tradesService.saveTrades(trades, userId);
			}else{
				orderService.submitcancel(token, orderId);
				send(userId, "手动卖出失败，系统已撤销撤消未完成订单");
			}
			
			
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e.getMessage());
		}
		
	}
	
	
	 private void send(Long userId,String message){
		    messageService.sendConsoleMessage(userId, message);
	  }
	
	
}
